package com.sc.datacollect.netty.server;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;

import org.apache.log4j.Logger;

import com.sc.datacollect.netty.model.ConfContent;
import com.sc.datacollect.netty.model.Shard;
import com.sc.datacollect.netty.model.ShardResult;
import com.sc.datacollect.util.Common;
import com.sc.datacollect.util.CommonConfig;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class FileTransferServerHandler extends ChannelInboundHandlerAdapter {
	
	private Logger log = Logger.getLogger(FileTransferServerHandler.class);
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		JSONObject result = new JSONObject();
		JSONObject resultData = new JSONObject();
		JSONArray missing = new JSONArray();
		try {
			JSONObject json = JSON.parseObject((String) msg);
			String method = json.getString("method");
			
			result.put("method", method);
			// 分片数据传输
			if ("shard".equals(method)) {
				ShardResult sf = JSON.parseObject(msg.toString(), ShardResult.class);
				
				resultData.put("index", sf.getIndex());
				resultData.put("size", sf.getSize());
				try {
					String path = CommonConfig.filepath + "temp/" + sf.getSubFileName();
					File file = new File(path);
					RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
					randomAccessFile.seek(0);
					randomAccessFile.write(sf.getBytes());
					
					result.put("code", Common.SUCCESSCODE);
					result.put("msg", "分片传输成功");
					result.put("data", resultData);

					file = null;
					randomAccessFile.close();
					randomAccessFile = null;
				} catch (Exception e) {
					result.put("code", Common.EXCEPTIONCODE);
					result.put("msg", "分片传输失败");
					result.put("data", resultData);
					e.printStackTrace();
				}
			}
			// 合并文件请求
			else if ("conf".equals(method)) {
				ConfContent conf = JSON.parseObject(msg.toString(), ConfContent.class);
				String path = CommonConfig.filepath;
				
				List<Shard> shards = conf.getShard();
				File tempPath = new File(path + "temp/");
				
				// 按照分片索引排序
				Collections.sort(shards, new Comparator<Shard>(){
					@Override
					public int compare(Shard o1, Shard o2) {
						return o1.getIndex() - o2.getIndex();
					}
				});
				
				List<FileInputStream> list = new ArrayList<FileInputStream>();
				
				File f = null;
				Shard part = null;
				for (int i = 0; i < shards.size(); i++) {
					part = shards.get(i);
					f = new File(tempPath, part.getSubFileName());
					if (f.exists()) {
						list.add(new FileInputStream(f));
					} else {
						// 分片数据缺失
						resultData = new JSONObject();
						resultData.put("index", part.getIndex());
						resultData.put("subFileName", part.getSubFileName());
						resultData.put("begin", part.getBegin());
						resultData.put("size", part.getSize());
						missing.add(resultData);
					}
				}
				
				if (missing.size() == 0) {
					Enumeration<FileInputStream> eum = Collections.enumeration(list);
					SequenceInputStream sis = new SequenceInputStream(eum);
					File vocfile = new File(new File(path), conf.getFileName());
					FileOutputStream fos = new FileOutputStream(vocfile);
					byte[] by = new byte[100];
					int len;
					while ((len = sis.read(by)) != -1) {
						fos.write(by, 0, len);
					}
					fos.flush();
					fos.close();
					sis.close();
					
					result.put("code", Common.SUCCESSCODE);
					result.put("msg", "合并完成");
					result.put("data", null);
					
					// 合并完成 删除分片文件
					for (int i = 0; i < shards.size(); i++) {
						f = new File(tempPath, shards.get(i).getSubFileName());
						f.delete();
					}
					
					log.info("::::::vocs文件合并完成，路径：" + vocfile.getPath());
				} else {
					result.put("code", Common.SHARDMISSING);
					result.put("msg", "分片数据缺失");
					result.put("data", missing);
				}
				
				list.clear();
				list = null;
			}
		} catch (Exception e) {
			log.info(e.getMessage());
			result.put("code", Common.EXCEPTIONCODE);
			result.put("msg", e.getMessage());
		} finally {
			ctx.writeAndFlush(result.toJSONString());
			
			result = null;
			resultData = null;
			missing = null;
		}
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		ctx.close();
	}
}
